今天來講一些集合上會用到的好用的函數
顧名思義,集合轉換(Collection Transformations)的意思就是針對集合內的元素,把原本的值轉換成另一種值。
map()
會針對集合內的元素,把原本的值轉換成另一種值。
透過原始碼,可以看到 map() 可以藉由一個 Iterable<T>
的 receiver
來呼叫,map 內可以接收一個 lambda function: transform
,最後回傳 List<R>
所以這個例子,會把 listOf(1, 2, 3, 4, 5) 每個數字乘以 10 後回傳 List 物件 ,結果會是 [10, 20, 30, 40, 50],也就是透過 map() 把 [1, 2, 3, 4, 5] 轉換成了 [10, 20, 30, 40, 50]
val newList = listOf(1, 2, 3, 4, 5).map { it * 10 }
println(newList) // [10, 20, 30, 40, 50]
由於原始碼宣告是<T,R>
而回傳是 List<R>
,代表回傳的型態和輸入可以不一樣
所以也可以是這樣的用法,輸入是數字,回傳是字串。
val newStrList = listOf(1, 2, 3, 4, 5).map<Int, String> { "value $it" }
println(newStrList) // [value 1, value 2, value 3, value 4, value 5]
flatMap() 的用意則是把資料打平的概念,也就是把多個 list 變成一個 list,很像是攤平的意思。
透過原始碼,也可以發現呼叫方式跟 map() 蠻相似的,差別在於 transform 這個 function 是回傳 Iterable。
如下面例子,val data 是兩個 List 合成的 List, flatMap {} 內還傳入了 it.map { it * 10} ,it.map {} 會回傳 List 所以會符合原始碼內的 transform: (T) -> Iterable<R>
的定義。
總之,最後把兩個 List 內的值都乘以 10 後,最後合併成一個 list。
val data = listOf(listOf(1, 2, 3, 4, 5), listOf(100, 101, 102, 103, 104))
val flatData2 = data.flatMap { it.map { it * 10 } }
println("data.flatMap *10:$flatData2")
// data.flatMap *10:[10, 20, 30, 40, 50, 1000, 1010, 1020, 1030, 1040]
不過其實如果只是要合併 List 成一個,不做其他動作的話,使用 flatten() 就可以了,下面的例子就只是單純把兩個 List 合併成一個。
val data = listOf(listOf(1, 2, 3, 4, 5), listOf(100, 101, 102, 103, 104))
val flatData = data.flatten()
println("data.flatten$flatData")
// data.flatten[1, 2, 3, 4, 5, 100, 101, 102, 103, 104]
filter() 接受一個 prdicate function ,這個 function 回傳值是 Boolean,也就是當滿足過濾的條件時,資料會被留下來
所以像這個例子,[1, 2, 3, 4, 5, 6] 滿足 % 2 為 0 的話,就會被保留下來,也就是 [2, 4, 6]
val filterResult = listOf(1, 2, 3, 4, 5, 6).filter { it % 2 == 0 }
println("filterResult:$filterResult")
// filterResult:[2, 4, 6]
針對一些 predicate function,還有這些方法可以使用
any() - 任一元素滿足條件,回傳 true
none() - 沒有任何元素滿足條件,回傳 true
all() - 全部元素滿足條件,回傳 true
所以針對下面的例子,val numbers = listOf("one", "two", "three", "four")
numbers.any { it.endsWith("e") } 因為有元素有結尾是 e 這個字,所以是 true
numbers.none { it.endsWith("a") } 沒有任何元素有結尾是 a,所以是 true
numbers.all { it.endsWith("e") } 全部元素並不是都是結尾是 e,所以是 false
val numbers = listOf("one", "two", "three", "four")
println(numbers.any { it.endsWith("e") }) // true
println(numbers.none { it.endsWith("a") }) // true
println(numbers.all { it.endsWith("e") }) // false
這裡有一個很棒的例子,展現了目前提到的方法的威力
首先,搞清楚質數的定義
質數:只能被 1 或 本身除盡的數,以 7 為例子,7 只能被 1 或 7 除盡,所以 7 是 質數
所以這裡其實 filter 的內容就是,以 7 為例子,就是跑 2~6,每個去做 7%2, 7%3, 7%4, 7%5, 7%6 看每個是不是都不能被除盡,那就回傳 true,代表是質數。
// 所以如果 7 % (2~6) == 0 => 不是質數
val nums = listOf(7, 4, 8, 4, 3)
val primes = nums.filter { num ->
(2 until num).map {
num % it
}.none { it == 0 } // Returns `true` if no elements match the given [predicate].
}
println("質數: $primes") // 質數: [7, 3]
如果對 until 不熟悉,可以查看官網的例子,很簡單 https://kotlinlang.org/docs/reference/ranges.html
partition() 可以把集合,針對 predicate 的 true false,分成兩群
val partitions = listOf(1, 2, 3, 4, 5, 6).partition { it % 2 == 0 }
println("partitions: $partitions")
//partitions: ([2, 4, 6], [1, 3, 5])
zip 會按照位置把兩個集合,合併成新的集合,新的集合長度會是原本兩個集合中比較短的那一個。
val z1 = listOf(1, 2, 3, 4, 5, 6)
val z2 = listOf(10, 20, 30)
val zipResult: List<Pair<Int, Int>> = z1.zip(z2)
println("zipResult: $zipResult")
//zipResult: [(1, 10), (2, 20), (3, 30)]
val reducedValue = listOf(1, 2, 3, 4).reduce { acc, num ->
println("reduced value: acc:$acc, num:$num")
acc + num
}
println("reducedValue final result: $reducedValue \n\n")
/*
reduced value: acc:1, num:2
reduced value: acc:3, num:3
reduced value: acc:6, num:4
reducedValue final result: 10
*/
val reducedValueRight = listOf(1, 2, 3, 4).reduceRight { num, acc ->
println("reduced value from Right: acc:$acc, num:$num")
acc + num
}
println("reducedValue from Right final result: $reducedValueRight \n\n")
/*
reduced value from Right: acc:4, num:3
reduced value from Right: acc:7, num:2
reduced value from Right: acc:9, num:1
reducedValue from Right final result: 10
*/
val foldedValue = listOf(1, 2, 3, 4).fold(100) { acc, num ->
println("accumulated value: acc:$acc, num:$num")
acc + num
}
println("foldedValue final result: $foldedValue \n\n")
/*
accumulated value: acc:100, num:1
accumulated value: acc:101, num:2
accumulated value: acc:103, num:3
accumulated value: acc:106, num:4
foldedValue final result: 110
*/
val foldedValueRight = listOf(1, 2, 3, 4).foldRight(100) { num, acc ->
println("accumulated value from Right: acc:$acc, num:$num")
acc + num
}
println("foldedValue final from Right result: $foldedValueRight \n\n")
/*
accumulated value from Right: acc:100, num:4
accumulated value from Right: acc:104, num:3
accumulated value from Right: acc:107, num:2
accumulated value from Right: acc:109, num:1
foldedValue final from Right result: 110
*/
以上就是今天的內容!謝謝大家!
今日練習的程式在這: 請點我